
# SCons File to compile QEMU

Import('qemu_env')
Import('qemu_target')
Import('ptlsim_lib')
Import('plugins')
Import('ptlsim_inc_dir')
import subprocess
import re
env = qemu_env
target = qemu_target

target_base_arch = "%s" % target['arch']
if target_base_arch == "x86_64":
    target_base_arch = "i386"

target_path = "%s/target-%s" % (env['source_path'], target_base_arch)
target_build_path = "%s/%s-softmmu" % (env['source_path'], target['arch'])
hw_path = "%s/hw" % env['source_path']
env['CPPPATH'] = []
env['CPPPATH'].append([".", "..", target_path, env['source_path']])
env['CPPPATH'].append(target['dir'])
env['CPPPATH'].append(ptlsim_inc_dir)
env.Append(CCFLAGS = "-MMD -MP -DNEED_CPU_H")
env.Append(CCFLAGS = "-DMARSS_QEMU")

GCC_VERSION = subprocess.Popen([env['CC'], '-dumpversion'],
    stdout=subprocess.PIPE).communicate()[0].strip()
GCC_MAJOR_MINOR_VERSION = re.match(r'\d*\.\d+',GCC_VERSION).group() #e.g. returns 4.2 for 4.2.2

num_sim_cores = ARGUMENTS.get('c', 1)
env.Append(CCFLAGS = '-DNUM_SIM_CORES=%d' % int(num_sim_cores))

debug = ARGUMENTS.get('debug', 0)
if int(debug):
    if int(debug) == 1:
        env.Append(CCFLAGS = '-g')
    elif int(debug) == 2:
        env.Append(CCFLAGS = '-ggdb3')
        env.Append(CCFLAGS = '-g3')
        if float(GCC_MAJOR_MINOR_VERSION) >= 4.8:
            env.Append(CCFLAGS = '-Og')
        else:
            env.Append(CCFLAGS = '-O0')
else:
    env.Append(CCFLAGS = '-O3 -march=native')

google_perftools = ARGUMENTS.get('gperf', None)
if google_perftools != None:
    env.Append(LIBS = 'tcmalloc')
    env.Append(LIBPATH = google_perftools)
    env.Append(LINKFLAGS = '-Wl,-rpath')
    env.Append(LINKFLAGS = '-Wl,%s' % google_perftools)


error_str = "failure"

# if compiling with g++ add -x c flag
if "g++" in env['CC'] :
    env.Append(CCFLAGS = "-x c")

# If we add user space emulator support then 
# add user space compilation from QEMU's makefile

qemu_prog_name = "qemu-system-%s" % target['arch']

# Set helper CFLAGS
HELPER_CFLAGS = ""
if target['arch'] == "i386":
    HELPER_CFLAGS += " -fomit-frame-pointer"

env.Append(CPPFLAGS = "-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \
        -D_LARGEFILE_SOURCE")
env.Append(LIBS = "m")

#######################
# QObject
q_object_files = "qint.c qstring.c qdict.c qlist.c qfloat.c qbool.c"
q_object_files += " qjson.c json-lexer.c json-streamer.c json-parser.c"
q_object_files += " qerror.c"

#######################
# oslib-obj
oslib_files = "osdep.c oslib-posix.c"

#######################
# block-obj
block_files = "cutils.c cache-utils.c qemu-malloc.c qemu-option.c module.c"
block_files += " nbd.c block.c aio.c aes.c"
block_files += " posix-aio-compat.c qemu-config.c"
if env['linux_aio'] == True:
    block_files += " linux-aio.c"

block_files += " " + " ".join(Glob("block/*.c", strings=True))
block_files = block_files.replace("block/raw-win32.c", "")
block_files = block_files.replace("block/rbd.c", "")
if env['curl'] == False:
    block_files = block_files.replace("block/curl.c ", " ")

net_files = "net.c "
net_files += " ".join(Glob("net/*.c", strings=True))
# This is hack, we compile only for linux so we remove all other system based
# net files without any check.
for file in ['tap-win32.c', 'tap-bsd.c', 'tap-aix.c', 'tap-solaris.c',
        'tap-haiku.c']:
    net_files = net_files.replace('net/%s' % file, "")

if env['slirp'] != True:
    net_files = net_files.replace('net/slirp.c', '')
if env['vde'] != True:
    net_files = net_files.replace('net/vde.c', '')

#######################
# fsdev-obj
fsdev_files = " ".join(Glob("fsdev/*.c", strings=True))

#######################
# libqemu_common.a

comm_lib_env = env.Clone()

comm_files = "readline.c console.c tcg-runtime.c host-utils.c ioport.c "
comm_hw_files = "irq.c i2c.c smbus.c smbus_eeprom.c eeprom93xx.c "
comm_hw_files += " scsi-disk.c cdrom.c scsi-generic.c scsi-bus.c "
comm_hw_files += " usb.c usb-hub.c usb-hid.c usb-desc.c "
comm_hw_files += " usb-msd.c usb-wacom.c usb-serial.c usb-net.c usb-bus.c "
comm_hw_files += " msmouse.c ps2.c qdev.c qdev-properties.c"
comm_hw_files += " bt.c bt-l2cap.c bt-sdp.c "
comm_hw_files += " bt-hci.c bt-hid.c usb-bt.c bt-hci-csr.c"
comm_hw_files += " event_notifier.c "

# List of files that are not going to used for x86[_64]
# max7310.c max111x.c wm8750.c twl92230.c tsc2005.c lm832x.c
# tmp105.c stellaris_input.c ads7846.c ssd0303.c ssd0323.c ds1338.c 
# ssi.c ssi-sd.c sd.c 

comm_files += " buffered_file.c migration.c migration-tcp.c "
comm_files += " qemu-sockets.c qemu-char.c"
comm_files += " savevm.c cache-utils.c bt-host.c bt-vhci.c"
comm_files += " usb-%s.c" % env['usb']
comm_files += " migration-exec.c migration-unix.c migration-fd.c"
comm_files += " block-migration.c blockdev.c cursor.c "
comm_files += " qemu-error.c input.c pflib.c "

# We only add POSIX/Linux related files
comm_files += " os-posix.c"

comm_libs = ""
comm_ldflags = ""
if env['brlapi']:
    comm_hw_files += " baum.c"
    comm_libs += " brlapi"

audio_files = "audio.c noaudio.c wavaudio.c mixeng.c"
audio_pt = False
audio_pt_int = False
if env['sdl'] == True:
    audio_files += " sdlaudio.c"
if 'oss' in env and env['oss']:
    audio_files += " ossaudio.c"
if 'coreaudio' in env and env['coreaudio']:
    audio_files += " coreaudio.c"
if 'alsa' in env and env['alsa']:
    audio_files += " alsaaudio.c"
if 'dsound' in env and env['dsound']:
    audio_files += " dsoundaudio.c"
if 'fmod' in env and env['fmod']:
    audio_files += " fmodaudio.c"
if 'esd' in env and env['esd']:
    audio_pt = True
    audio_pt_int = True
    audio_files += " esdaudio.c"
if 'pa' in env and env['pa']:
    audio_pt = True
    audio_pt_int = True
    audio_files += " paaudio.c"

if audio_pt:
    comm_ldflags = "-pthread"
if audio_pt_int:
    audio_files += " audio_pt_int.c"

audio_files += " wavcapture.c"
audio_list = []
for a_f in Split(audio_files):
    audio_list.append("audio/%s" % a_f)

ui_files = " keymaps.c"
if env['sdl'] == True:
    ui_files += " sdl.c sdl_zoom.c x_keymap.c"
    comm_lib_env.ParseConfig("sdl-config --cflags")
if env['curses'] == True:
    ui_files += " curses.c"
ui_files += " vnc.c d3des.c vnc-enc-zlib.c "
ui_files += " vnc-enc-hextile.c vnc-enc-tight.c vnc-palette.c "
if env['vnc_tls'] == True:
    ui_files += " vnc-tls.c vnc-auth-vencrypt.c"
if env['vnc_sasl'] == True:
    ui_files += " vnc-auth-sasl.c"
if env['vnc_thread'] == True:
    ui_files += " vnc-jobs-async.c"
else:
    ui_files += " vnc-jobs-sync.c"

ui_list = []
for ui_file in Split(ui_files):
    ui_list.append("ui/%s" % ui_file)

# if env['cocoa'] == True:
    # comm_files += " cocoa.c"
if env['iothread'] == True:
    comm_files += " qemu-thread.c"

comm_files += " acl.c iov.c"
comm_files += " notify.c "
comm_files += " qemu-timer.c qemu-timer-common.c"

slirp_files = " "
if env['slirp'] == True:
    slirp_files = " ".join(Glob('slirp/*.c', strings=True))
    comm_lib_env['CPPPATH'].append("slirp")

if env['xen'] == True:
    comm_files += " xen_backend.c xen_devconfig.c xen_console.c xenfb.c"
    comm_files += " xen_disk.c xen_nic.c"

comm_hw_list = []
for h in Split(comm_hw_files):
    comm_hw_list.append("hw/%s" % h)

q_objs = comm_lib_env.Object(Split(q_object_files))
block_objs = comm_lib_env.Object(Split(block_files))
net_objs = comm_lib_env.Object(Split(net_files))
oslib_objs = comm_lib_env.Object(Split(oslib_files))

comm_lib_env['CPPPATH'].append("fpu")
libqemu_comm = comm_lib_env.Library('qemu_common', Split(comm_files) +
        audio_list + Split(slirp_files) + comm_hw_list + block_objs +
        net_objs + q_objs + ui_list + oslib_objs)

#######################
# Qemu Binary Builder

qemu_bld_action = "$CC $_LIBDIRFLAGS $LINKFLAGS -o $TARGET $SOURCES $ARLIB_BEGIN $ARLIB $ARLIB_END $_LIBFLAGS"
qemu_bld = Builder(action = Action(qemu_bld_action,
    cmdstr="$LINKCOMSTR"))
comm_lib_env['BUILDERS']['QEMU_BIN'] = qemu_bld
env['BUILDERS']['QEMU_BIN'] = qemu_bld

hxtool_bld = "sh %s/scripts/hxtool -h < $SOURCE > $TARGET" % env['source_path']
env['BUILDERS']['HXTOOL'] = Builder(action = Action(hxtool_bld,
    cmdstr="$CREATECOMSTR"))

#######################
# qemu-img :

# qemu-img-cmds.h
qemu_img_cmds_h = env.HXTOOL('qemu-img-cmds.h', 'qemu-img-cmds.hx')

# osdep_o = env.Object("osdep.c")
qemu_tool_o = comm_lib_env.Object("qemu-tool.c")
qemu_err_o = comm_lib_env.Object("qemu-error.c")
qemu_timer_comm_o = comm_lib_env.Object("qemu-timer-common.c")
qemu_img_comm_objs = qemu_tool_o + block_objs + q_objs + oslib_objs
qemu_img_comm_objs += qemu_err_o
qemu_img_comm_objs += qemu_timer_comm_o
qemu_img_o = comm_lib_env.Object("qemu-img.c")

qemu_img = comm_lib_env.QEMU_BIN('qemu-img', 
        qemu_img_o + qemu_img_comm_objs,
        LIBS = comm_lib_env['LIBS'] + ["z"])

qemu_nbd_o = comm_lib_env.Object("qemu-nbd.c")
qemu_nbd = comm_lib_env.QEMU_BIN('qemu-nbd',
        qemu_nbd_o + qemu_img_comm_objs,
        LIBS = comm_lib_env['LIBS'] + ["z"])

qemu_io_o = comm_lib_env.Object(Split("qemu-io.c cmd.c"))
qemu_io = comm_lib_env.QEMU_BIN('qemu-io',
        qemu_io_o + qemu_img_comm_objs,
        LIBS = comm_lib_env['LIBS'] + ["z"])

#######################
# cpu emulator library

cpu_emu_objs = "exec.c translate-all.c "
cpu_emu_objs += " %s/translate.c" % target_path
# TCG code generator
cpu_emu_objs += " tcg/tcg.c" # tcg/tcg-runtime.c"
cpu_emu_objs += " %s/cpuid.c" % target_path
env['CPPPATH'].append("%s/tcg" % env['source_path'])
env['CPPPATH'].append("%s/tcg/%s" % (env['source_path'], target_base_arch))

if target['softfloat']:
    cpu_emu_objs += " fpu/softfloat.c"
else:
    cpu_emu_objs += " fpu/softfloat-native.c"

env['CPPPATH'].append("%s/fpu" % env['source_path'])

op_helper_obj = env.Object('%s/op_helper.c' % target_path, 
        CCFLAGS = env['CCFLAGS'] + HELPER_CFLAGS)
helper_obj = env.Object('%s/helper.c' % target_path,
        CCFLAGS = env['CCFLAGS'] + HELPER_CFLAGS)
cpu_exec_obj = env.Object('cpu-exec.c', 
        CCFLAGS = env['CCFLAGS'] + HELPER_CFLAGS)

cpu_emu_objs += " %s/op_helper.o %s/helper.o" % (target_path, target_path)
cpu_emu_objs += " cpu-exec.o"

if target['user_only']:
    cpu_emu_objs += " mmu.c"

# disassembler code needed for debugging only
cpu_emu_objs += " disas.c"
# We are compiling for i386 or x86_64 only so set USE_I386_DIS to true
USE_I386_DIS = True
cpu_emu_objs += " i386-dis.c"

# libqemu
libqemu = env.Library('qemu', Split(cpu_emu_objs))

# Make sure that linux_user flag is not set
if target['linux_user']:
    print("ERROR: Linux user flag is set.")
    print("This configuration is not supported in MARSSx86")
    Return('error_str')

if target['darwin_user']:
    print("ERROR: Darwin user flag is set.")
    print("This configuration is not supported in MARSSx86")
    Return('error_str')

if target['user_only']:
    print("ERROR: user mode flag is set.")
    print("This configuration is not supported in MARSSx86")
    Return('error_str')

obj_files = "async.c monitor.c dma-helpers.c"
obj_files += " %s/machine.c" % target_path
obj_files += " cpus.c arch_init.c balloon.c "
obj_files += " rwhandler.c"
hw_files = "pci.c isa_mmio.c pci_host.c loader.c sysbus.c isa-bus.c"
hw_files += " pci_bridge.c msi.c pcie_host.c "
hw_files += " ioh3420.c xio3130_upstream.c xio3130_downstream.c qdev-addr.c "
# hw_files += " ecc.c nand.c"
# virtio in hw
hw_files += " virtio.c virtio-pci.c virtio-blk.c virtio-balloon.c"
hw_files += " virtio-net.c virtio-console.c virtio-serial-bus.c"
hw_files += " vhost_net.c"
hw_files += " fw_cfg.c watchdog.c wdt_i6300esb.c msix.c "

if env['kvm']:
    obj_files += " kvm-all.c"
    obj_files += " %s/kvm.c" % target_path
else:
    obj_files += " kvm-stub.c"

#if env['aio']:
#    obj_files += " posix-aio-compat.c"
#else:
#    obj_files += " block-raw-posix.c"

env.Append(LIBS = "z")

# Audio configuration - Not converted fully
if env['aud_lib'] != "":
    env.Append(LIBS = env['aud_lib'])

sound_hw_files = "sb16.c es1370.c ac97.c"

if 'adlib' in env:
    sound_hw_files += " fmopl.o adlib.o"
    adlib_obj = env.Object('hw/adlib.c',
            CCFLAGS = env['CCFLAGS'] + "-DBUILD_Y8950=0")
    fpmol_obj = env.Object('hw/fpmol.c',
            CCFLAGS = env['CCFLAGS'] + "-DBUILD_Y8950=0")

if 'gus' in env:
    sound_hw_files += " gus.c gusemu_hal.c gusemu_mixer.c"

if 'cs4231a' in env:
    sound_hw_files += " cs4231a.c"

hw_files += " %s" % sound_hw_files
# VNC TLS flags are added in configuration
#if env['vnc_tls']:

# Bluez flags are added in configuration

hw_files += " lsi53c895a.c esp.c"
hw_files += " usb-ohci.c"
# hw_files += " eeprom93xx.c"
hw_files += " eepro100.c ne2000.c pcnet-pci.c pcnet.c rtl8139.c e1000.c"
# hw_files += " msmouse.c"

if target_base_arch == "i386":
    hw_files += " pckbd.c vga.c dma.c vga-isa.c vga-pci.c ioapic.c"
    hw_files += " fdc.c mc146818rtc.c serial.c i8259.c i8254.c acpi_piix4.c "
    hw_files += " pcspk.c pc.c cirrus_vga.c apic.c parallel.c acpi.c smbios.c"
    hw_files += " piix_pci.c usb-uhci.c vmmouse.c vmport.c ne2000-isa.c"
    hw_files += " vmware_vga.c hpet.c device-hotplug.c pci-hotplug.c"
    hw_files += " pm_smbus.c apm.c"
    hw_files += " multiboot.c debugcon.c "
    hw_files += " pc_piix.c"
    env.Append(CPPFLAGS = " -DHAS_AUDIO -DHAS_AUDIO_CHOICE")
else:
    print("ERROR: Unsupported arch.")
    print("MARSSx86 Only supports x86_64 architecture")

hw_files += " pcie.c pcie_aer.c pcie_port.c "

ide_files = " ".join(env.Glob("hw/ide/*.c", strings=True))

# remove mac io file from ide
ide_files = ide_files.replace("hw/ide/macio.c", "")

if env['gdbstub']:
    obj_files += " gdbstub.c"
    # We are not including any gdbstub xml files as 
    # its not required in arch that we support

##########################
# trace - is disabled

trace_h_bld = "%s/scripts/tracetool --nop -h < $SOURCE > $TARGET " % env['source_path']
trace_c_bld = "%s/scripts/tracetool --nop -c < $SOURCE > $TARGET " % env['source_path']

env['BUILDERS']['TRACE_H_CR'] = Builder(action = Action(trace_h_bld,
    cmdstr="$CREATECOMSTR"))
env['BUILDERS']['TRACE_C_CR'] = Builder(action = Action(trace_c_bld,
    cmdstr="$CREATECOMSTR"))

trace_h = env.TRACE_H_CR('trace.h', 'trace-events')
trace_c = env.TRACE_C_CR('trace.c', 'trace-events')

##########################
# qemu-options.def
qemu_options_def = env.HXTOOL('qemu-options.def', 'qemu-options.hx')

# qemu-monitor.h
# qemu_monitor_h = env.HXTOOL('qemu-monitor.h', 'qemu-monitor.hx')

# hmp-commands.h
hmp_commands_h = env.HXTOOL('hmp-commands.h', 'hmp-commands.hx')

# qmp-commands.h
qmp_commands_h = env.HXTOOL('qmp-commands.h', 'qmp-commands.hx')

##########################
# pc-bios and option-rom
Export('env')
pc_bios_objs = SConscript('%s/pc-bios/SConscript' % env['source_path'])
SConscript('%s/pc-bios/optionrom/SConscript' % env['source_path'])

# We dont support cocoa yet, if we do in future then add 
# LIB and CLFAGS for cocoa

if env['slirp']:
    env['CPPPATH'].append("%s/slirp" % env['source_path'])

if env['static']:
    env.Append(LINKFLAGS = "-static")

env.Append(LIBS = "util")

if env['gprof']:
    vl_obj = env.Object('vl.c', CCFLAGS = env['CCFLAGS'] + "-p")
    obj_files += " vl.o"
    env.Append(LINKFLAGS = "-p")
else:
    obj_files += " vl.c"

hw_files_list = []
for hw_f in Split(hw_files):
    hw_files_list.append("hw/%s" % hw_f)

hw_files_o = env.Object(Split(obj_files) + hw_files_list + Split(ide_files))
trace_o = env.Object(trace_c)

env.Append(LIBPATH = "%s/../plugins" % env['source_path'])
env.Append(LINKFLAGS = "-Wl,-rpath=%s/../plugins" % env['source_path'])
env.Append(LINKFLAGS = "-Wl,--no-as-needed")
env.Append(LIBS = plugins)
env['ARLIB'] = libqemu_comm + libqemu + ptlsim_lib
qemu_bin = env.QEMU_BIN(qemu_prog_name, hw_files_o + pc_bios_objs +
        trace_o)
env.Depends(qemu_bin, env['ARLIB'])

# print env.Dump()

Return('qemu_bin')
